#include "path.hpp"
namespace chen {
PathShader::PathShader(
    const Scene * sce, const Camera * cam, Sampler * samp,
    int split, int nls, int mbc
): SamplerShader(sce, cam, samp, split), nlight_samples(nls), max_bounce(mbc) {}

void PathShader::prepare (int ntr) {
    SamplerShader::prepare(ntr);
    LOG(INFO) << "[Path Shader] using path shader.";
}


Spectrum PathShader::Li (const Ray & _r, Sampler * sampler) const {
    Spectrum beta = 1.0f; // 贡献因子
    // Float beta_canceliation = 1.0f; // TODO
    Spectrum ret = 0;
    SurfInteract si;
    Ray r = _r;
    int bounces = 0;
    bool deltaDist = false;
    while(true) {
        if(!this->scene->castRay(r, &si)) {
            for(
                auto it = this->scene->lights.begin();
                it != this->scene->lights.end(); it++
            )
                ret += beta*((*it)->LeFrom(r));
            break;
        } else if(bounces == 0 || deltaDist) ret += beta*si.Le();
        //puts("hit!");
        if(bounces > max_bounce) break;
        bounces ++;
        deltaDist = si.hasFlag(FBSDF_DELTA);
        //if(abs(beta.maxComponent()) > 10) printf("bt:%f\n", beta.maxComponent());
        ret += beta*estimateDirectIlluminationND(si, nlight_samples, sampler);
        // 接下来来开始构建增量路径
        Vector3 wi;
        Float pdf;
        Spectrum f = si.sampleBSDF(si.wo, sampler->gen2D(), &wi, &pdf);
        beta = beta*f*abs(dot((Vector3)si.n, wi))/pdf;
        r = si.spawnRayPickSide(-wi);
        //if(abs(ret.maxComponent()) > 10) printf("%f\n", ret.maxComponent());
        if(bounces > 3) {
            Float q = max((Float)0.05, 1-beta.maxComponent());
            if(sampler->gen() < q) break ;
            beta = beta/(1-q);
        }
    }
    return ret;
}

}